#pragma once

/*
	File:	DirectX.h
	Author: TJ Ashby

	Comments:
		Macros and typedefs to make things extremely simple
*/

#include <d3d9.h>
#include <d3dx9.h>
#include <limits.h>

#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")

// Macros
typedef void* Pointer;
typedef LPSTR String;
#define IsKeyPressed(key) GetAsyncKeyState(key)

#define LSHIFTONE << 1
#define LSHIFTTWO << 2
#define LSHIFTTHREE << 3
#define LSHIFTFOUR << 4
#define RSHIFTONE >> 1
#define RSHIFTTWO >> 2
#define RSHIFTTHREE >> 3
#define RSHIFTFOUR >> 4

typedef RECT Rect;
typedef D3DXMATRIX	 Matrix;
typedef D3DXVECTOR2  Vector2;
typedef D3DXVECTOR3  Vector3;
typedef D3DXVECTOR4  Vector4;
typedef D3DXCOLOR    Color; // 'ARGB'
typedef ID3DXLine*	 Line;
typedef ID3DXEffect* Shader;
typedef ID3DXMesh 	 Mesh;
typedef IDirect3DTexture9* Texture; // Holds the contents of an image for use in texturing 3D objects, or just displaying sprites/images.
typedef D3DXFRAME* ModelFrame; // A model has 1 or more frames, this holds a single frame. Useful for transforming a specific part of a 3D object.
typedef IDirect3DVertexBuffer9* VertexBuffer; // Holds the vertices needed to build a 3D object
typedef IDirect3DVertexDeclaration9* VertexDeclaration; // Holds the contents that are contained with each vertex
typedef IDirect3DIndexBuffer9* IndexBuffer; // Holds the order of which the vertices are drawn

#define CreateColor(r,g,b)   D3DCOLOR_ARGB(0xff,r,g,b) // Creates a 'Color' object
#define ToRadian(Degree)	D3DXToRadian(Degree)
#define ToDegree(Radian)	D3DXToDegree(Radian)

#define SAFE_RELEASE(p)  if(p) p->Release()
#define SAFE_DELETE(p)	if(p) delete p; p = nullptr
#define SAFE_DELETE_ARRAY(p) if(p) delete [] p; p = nullptr
#define SAFE(p) if(p)
#define NOID -1
#define NONE	NULL
#define ZERO	NONE


/************************************************************************/
/* DEBUGGING                                                                     */
/************************************************************************/
// Set the program's entry point to either Console "main" or Windows "WinMain":
#if defined(_DEBUG)
#pragma comment(linker, "/SUBSYSTEM:Console")
#else
#pragma comment(linker, "/SUBSYSTEM:Windows")
#endif

// Prepare to write to the console window at any time
#ifdef _DEBUG
#include <iostream>
	using namespace std;
#endif
/***********************************************************************/

#define IdentityMatrix(matrix) D3DXMatrixIdentity(&matrix) // Create an Identity matrix { 1,0,0,0,1,0,0,0,1,0,0,0,1 }
#define TranslateMatrix(matrix,X,Y,Z)	D3DXMatrixTranslation(&matrix,X,Y,Z) // Set a matrix to a certain position {  1,0,0,0,1,0,0,0,1,0,X,Y,Z,1 }
#define ScaleAMatrix(matrix,ScaleX,ScaleY,ScaleZ)		D3DXMatrixScaling(&matrix,ScaleX,ScaleY,ScaleZ) // Scales a matrix,Basically scales the object you are rendering
#define ScaleMatrix(matrix,Scale)		D3DXMatrixScaling(&matrix,Scale,Scale,Scale); // Scales a matrix,Basically scales the object you are rendering
#define RotateX(rotationMatrix,angle)	D3DXMatrixRotationX(&rotationMatrix,angle) // Rotate a matrix on the X axis - Roll
#define RotateY(rotationMatrix,angle)	D3DXMatrixRotationY(&rotationMatrix,angle) // Rotate a matrix on the Y axis - Yaw
#define RotateZ(rotationMatrix,angle)	D3DXMatrixRotationZ(&rotationMatrix,angle) // Rotate a matrix on the Z axis - Pitch

namespace
{
	void Rotate_X(Matrix &mat,float Angle)
	{
		Matrix rot;

		RotateX(rot,Angle);

		mat = rot * mat;
	}
	void Rotate_Y(Matrix &mat,float Angle)
	{
		Matrix rot;

		RotateY(rot,Angle);

		mat = rot * mat;
	}
	void Rotate_Z(Matrix &mat,float Angle)
	{
		Matrix rot;

		RotateZ(rot,Angle);

		mat = rot * mat;
	}
	void Scale_Matrix(Matrix &mat,float Scale)
	{
		Matrix scale;
		ScaleMatrix(scale,Scale);

		mat = scale * mat;
	}
	unsigned short RandomHigh(unsigned short Modulus = USHRT_MAX)
	{
		unsigned short value = ((rand()%Modulus) | (rand()%Modulus));
		if(value > Modulus)
			value = Modulus;

		return value;
	}
	unsigned short RandomLow(unsigned short Modulus = USHRT_MAX)
	{
		unsigned short value = ((rand()%Modulus) & (rand()%Modulus));
		if(value > Modulus)
			value = Modulus;

		return value;
	}
}

// Vertex - Holds a position,normal, and uv - normal is the direction of a vector - uv is the coordinates for the texture used
struct Vertex
{
	Vector3 position;
	Vector3 normal;
	Vector2 uv;
};

// Pre-processor defines for the mouse buttons
enum
{
	LeftButton,RightButton,Middle_Button
};

// Virtual Keys for the keyboard
#define keyUp		DIK_UP
#define keyDown		DIK_DOWN
#define keyLeft		DIK_LEFT
#define keyRight	DIK_RIGHT
#define keyEscape	DIK_ESCAPE
#define keyEnter	DIK_RETURN
#define keyBackspace DIK_BACKSPACE
#define keyA		DIK_A
#define keyS		DIK_S
#define keyD		DIK_D
#define keyW		DIK_W
#define keyP		DIK_P
#define keySpace	DIK_SPACE
#define keyC		DIK_C
#define keyZ		DIK_Z
#define keyX		DIK_X
#define keyV		DIK_V
#define keyB		DIK_B
#define key1		DIK_1
#define key0		DIK_0
#define key2		DIK_2
#define key3		DIK_3
#define key4		DIK_4
#define key5		DIK_5
#define key6		DIK_6
#define key7		DIK_7
#define key8		DIK_8
#define key9		DIK_9
#define keyF1		DIK_F1
#define keyF2		DIK_F2
#define keyF3		DIK_F3
#define keyF4		DIK_F4
#define keyF5		DIK_F5
#define keyF6		DIK_F6
#define keyF7		DIK_F7
#define keyF8		DIK_F8
#define keyF9		DIK_F9
#define keyF10		DIK_F10
#define keyF11		DIK_F11
#define keyF12		DIK_F12
#define keyE		DIK_E
#define keyG		DIK_G
#define keyQ		DIK_Q
#define keyR		DIK_R
#define keyF		DIK_F
#define keyT		DIK_T
#define keyY		DIK_Y
#define keyU		DIK_U
#define keyI		DIK_I
#define keyO		DIK_O
#define keyH		DIK_H
#define keyJ		DIK_J
#define keyK		DIK_K
#define keyL		DIK_L
#define keyColon	DIK_COLON
#define keyQuote	DIK_APPS
#define keyN		DIK_N
#define keyM		DIK_M
#define keyComma	DIK_COMMA
#define keyLShift	DIK_LSHIFT
#define keyRShift	DIK_RSHIFT
#define keyLControl DIK_LCONTROL
#define keyRControl DIK_RCONTROL
#define keyNumPad0	DIK_NUMPAD0
#define keyNumPad1	DIK_NUMPAD1
#define keyNumPad2	DIK_NUMPAD2
#define keyNumPad3	DIK_NUMPAD3
#define keyNumPad4	DIK_NUMPAD4
#define keyNumPad5	DIK_NUMPAD5
#define keyNumPad6	DIK_NUMPAD6
#define keyNumPad7	DIK_NUMPAD7
#define keyNumPad8	DIK_NUMPAD8
#define keyNumPad9	DIK_NUMPAD9
